/* Copyright 2001,2002,2003 NAH6 BV
 * All Rights Reserved
 *
 *  $Header: /var/lib/cvs/secphone/ui/database/CeRecord.cpp,v 1.6 2003/11/21 12:39:24 itsme Exp $
 *
 *
 *  this class is used to build records, to be loaded/stored
 *  in a WinCE database
 *
 */

#include <windows.h>    // for windbase.h

#include "debug.h"

#include "CeRecord.h"

void CeRecord::Initialize(int nProps)
{
    m_nMaxProperties= nProps;
    m_props= new CEPROPVAL[nProps];
    memset((void*)m_props, 0, sizeof(CEPROPVAL)*nProps);
    m_nProperties= 0;
    m_oid= 0;

    m_nUpdatedProperties= -1;
    m_updatedProps= NULL;
}

CeRecord::CeRecord(int nProps)
{
    Initialize(nProps);
}

CeRecord::CeRecord(CEOID oid, const CEPROPVAL *props, int nProps)
{
    Initialize(nProps+4);  //!!! until I convert this file to use STL, max 4 new fields can be added
    CopyPropValArray(props, nProps);
    m_oid= oid;
}

CeRecord::CeRecord(const CeRecord &rec)
{
    Initialize(rec.NrOfFields());
    CopyPropValArray(rec.PropValArray(), rec.NrOfFields());
    m_oid= rec.m_oid;
}

void CeRecord::CopyPropValArray(const CEPROPVAL *props, int nProps)
{
    for (int i=0 ; i<nProps; i++)
    {
        const CEPROPVAL *pv= &props[i];

        if (pv->propid==0x130013) 
            debug("!!");
        int fieldid= (pv->propid>>16)&0xffff;
        int fieldtype= pv->propid&0xffff;
        switch(fieldtype)
        {
            case CEVT_I2:
            case CEVT_UI2:
            case CEVT_I4:
            case CEVT_UI4:
            case CEVT_BOOL:
                AddValueEx2(pv->propid, pv->val.ulVal);
                break;
            case CEVT_FILETIME:    
                AddTimestamp(pv->propid, &pv->val.filetime);
                break;
            case CEVT_LPWSTR:
                AddString(pv->propid, pv->val.lpwstr);
                break;
            case CEVT_BLOB:
            case CEVT_R8:
            default:
                /*nop*/;
                //debug("WARNING: ignoring field %04lx.%04lx\n", fieldid, fieldtype);
        }
    }

    // clear any 'modified' flags
    for (int i=0 ; i<m_nMaxProperties ; i++)
        m_props[i].wFlags= 0;
}

void DeleteProperties(CEPROPVAL *props, int nProperties, bool bDeleteStrings)
{
    for (int i=0 ; i<nProperties ; i++)
    {
        CEPROPVAL *pv= &props[i];
        int fieldtype= pv->propid&0xffff;
        if (bDeleteStrings 
                && fieldtype == CEVT_LPWSTR 
                && pv->val.lpwstr!=0)
        {
            delete pv->val.lpwstr;
        }
    }
    delete props;
}
CeRecord::~CeRecord()
{
    DeleteProperties(m_updatedProps, m_nUpdatedProperties, false);
    DeleteProperties(m_props, m_nMaxProperties, true);
}

int CeRecord::FindFieldIndex(CEPROPID field)
{
    for (int i=0 ; i<m_nMaxProperties ; i++)
    {
        if (m_props[i].propid==field)
            return i;
    }
    return -1;
}
WCHAR *CeRecord::GetString(CEPROPID field)
{
    int i= FindFieldIndex(field);
    if (i>=0)
        return m_props[i].val.lpwstr;

    return NULL;
}
void CeRecord::SetString(CEPROPID field, WCHAR *szValue)
{
    int i= FindFieldIndex(field);
    if (i>=0)
    {
        WCHAR *wbuf= new WCHAR[wcslen(szValue)+1];
        wcscpy(wbuf, szValue);

        m_props[i].val.lpwstr= wbuf;
        m_props[i].wFlags |= NHDB_MODIFIED;
    }
    else
    {
        AddString(field, szValue);
    }
}

bool CeRecord::AddString(CEPROPID field, const WCHAR *szValue)
{
    if (m_nProperties==m_nMaxProperties)
    {
        debug("ERROR: added too many properties\n");
        return false;
    }

    WCHAR *wbuf= new WCHAR[wcslen(szValue)+1];
    wcscpy(wbuf, szValue);

    return AddStringEx(field, wbuf);
}

bool CeRecord::AddString(CEPROPID field, const char *szValue)
{
    if (m_nProperties==m_nMaxProperties)
    {
        debug("ERROR: added too many properties\n");
        return false;
    }

    WCHAR *wbuf= new WCHAR[strlen(szValue)+1];
    swprintf(wbuf, L"%hs", szValue);

    return AddStringEx(field, wbuf);
}

bool CeRecord::AddStringEx(CEPROPID field, WCHAR *szValue)
{
    CEPROPVAL *pv= &m_props[m_nProperties];

    pv->propid= field; // (field<<16) | CEVT_LPWSTR;
    pv->wLenData= 0;
    pv->wFlags |= NHDB_MODIFIED;
    pv->val.lpwstr= szValue;

    ++m_nProperties;

    return true;
}
bool CeRecord::AddUInt16(CEPROPID field, DWORD nValue)
{
    return AddValueEx2(field, /*CEVT_UI2,*/ nValue);
}
bool CeRecord::AddUInt32(CEPROPID field, DWORD nValue)
{
    return AddValueEx2(field, /*CEVT_UI4,*/ nValue);
}
bool CeRecord::AddSInt16(CEPROPID field, long nValue)
{
    return AddValueEx2(field, /*CEVT_I2,*/ nValue);
}
bool CeRecord::AddSInt32(CEPROPID field, long nValue)
{
    return AddValueEx2(field, /*CEVT_I4,*/ nValue);
}
bool CeRecord::AddBoolean(CEPROPID field, BOOL nValue)
{
    return AddValueEx2(field, /*CEVT_BOOL,*/ nValue);
}


bool CeRecord::AddValueEx(int field, int type, DWORD nValue)
{
    if (m_nProperties==m_nMaxProperties)
    {
        debug("ERROR: added too many properties\n");
        return false;
    }

    CEPROPVAL *pv= &m_props[m_nProperties];

    pv->propid= (field<<16) | type;
    if (pv->propid==0x130013) 
        debug("!!");
    pv->wLenData= 0;
    pv->wFlags |= NHDB_MODIFIED;
    pv->val.ulVal= nValue;

    ++m_nProperties;

    return true;
}

bool CeRecord::AddValueEx2(CEPROPID field, DWORD nValue)
{
    if (m_nProperties==m_nMaxProperties)
    {
        debug("ERROR: added too many properties\n");
        return false;
    }

    CEPROPVAL *pv= &m_props[m_nProperties];

    pv->propid= field;
    if (pv->propid==0x130013) 
        debug("!!");

    pv->wLenData= 0;
    pv->wFlags |= NHDB_MODIFIED;
    pv->val.ulVal= nValue;

    ++m_nProperties;

    return true;
}

bool CeRecord::AddTimestamp(CEPROPID field, const FILETIME *ft)
{
    if (m_nProperties==m_nMaxProperties)
    {
        debug("ERROR: added too many properties\n");
        return false;
    }

    CEPROPVAL *pv= &m_props[m_nProperties];

    pv->propid= field; // (field<<16) | CEVT_FILETIME;
    if (pv->propid==0x130013) 
        debug("!!");

    pv->wLenData= 0;
    pv->wFlags |= NHDB_MODIFIED;

    memcpy(&pv->val.filetime, ft, sizeof(FILETIME));

    ++m_nProperties;

    return true;
}

int CeRecord::NrOfFields() const
{
    return m_nProperties;
}

CEPROPVAL *CeRecord::PropValArray() const
{
    return m_props;
}

void CeRecord::GetUpdatedProps()
{
    int count=0;
    int i;
    for (i=0 ; i<m_nProperties ; i++)
    {
        if (m_props[i].wFlags&NHDB_MODIFIED)
            count++;
    }
    m_nUpdatedProperties= count;
    m_updatedProps= new CEPROPVAL[count];

    int j=0;
    for (i=0 ; i<m_nProperties ; i++)
    {
        if (m_props[i].wFlags&NHDB_MODIFIED)
        {
            memcpy((void*)&m_updatedProps[j], (void*)&m_props[i], sizeof(CEPROPVAL));
            if ((m_updatedProps[j].propid&0xffff)==CEVT_LPWSTR)
                debug("  updated %08lx '%ls'\n", m_updatedProps[j].propid, m_updatedProps[j].val.lpwstr);
            else
                debug("  updated %08lx %08lx\n", m_updatedProps[j].propid, m_updatedProps[j].val.ulVal);

            m_updatedProps[j].wFlags= 0;

            j++;
        }
    }
}

int CeRecord::NrOfUpdatedFields()
{
    if (m_nUpdatedProperties<0)
        GetUpdatedProps();
    return m_nUpdatedProperties;
}

CEPROPVAL *CeRecord::UpdatedPropValArray()
{
    if (m_nUpdatedProperties<0)
        GetUpdatedProps();
    return m_updatedProps;
}


